﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Happy.Domain;
using Happy.StateManager;

namespace Happy.Examples.ManufactureManagement.Domain.Bases
{
    public abstract class MIAggregateRoot<TItem> : AggregateRoot<Guid>
    {
        protected MIAggregateRoot()
        {
            this.StateMache =
                StateMachine<Status, Operation>
                .Config(() => this.Status, status => this.Status = status)
                .In(Status.UnSaved).When(Operation.Save).If(CanSave).TransferTo(Status.Saved)
                .In(Status.UnSaved).When(Operation.Edit).Aways().Ok()
                .In(Status.Saved).When(Operation.Submit).If(this.CanSubmit).TransferTo(Status.Submitted)
                .In(Status.Saved).When(Operation.Edit).Aways().Ok()
                .In(Status.Submitted).When(Operation.Verify).If(this.CanVerify).TransferTo(Status.Verified)
                .Done();

            // ReSharper disable DoNotCallOverridableMethodsInConstructor
            this.Items = new Collection<TItem>();
            // ReSharper restore DoNotCallOverridableMethodsInConstructor
        }

        protected StateMachine<Status, Operation> StateMache { get; private set; }

        protected internal virtual ICollection<TItem> Items { get; protected set; }

        internal Status Status { get; set; }

        protected virtual bool CanSave()
        {
            return true;
        }

        protected virtual bool CanSubmit()
        {
            return true;
        }

        protected virtual bool CanVerify()
        {
            return true;
        }

        internal void Save()
        {
            this.StateMache.Schedule(Operation.Save);
        }

        internal void Submit()
        {
            this.StateMache.Schedule(Operation.Submit);
        }

        internal void Verify()
        {
            this.StateMache.Schedule(Operation.Verify);
        }

        internal void AddItem(TItem item)
        {
            this.AddItems(new List<TItem> { item });
        }

        internal void AddItems(IEnumerable<TItem> items)
        {
            this.StateMache.Schedule(Operation.Edit);

            foreach (var item in items)
            {
                this.Items.Add(item);
            }
        }

        internal void DeleteItem(TItem item)
        {
            this.DeleteItems(new List<TItem> { item });
        }

        internal void DeleteItems(IEnumerable<TItem> items)
        {
            this.StateMache.Schedule(Operation.Edit);

            foreach (var item in items)
            {
                this.Items.Remove(item);
            }
        }
    }
}
